package com.zsp.comic.config;

import com.zsp.comic.config.handler.*;
import com.zsp.comic.config.myHandler.MyAccessDeniedHandler;
import com.zsp.comic.config.myHandler.MyAuthenticationSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * @author gan
 * @create 2020-12-03 21:28
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private DataSource dataSource;

    @Resource
    private PersistentTokenRepository persistentTokenRepository;

    //异常处理
    @Resource
    private CustomizeAuthenticationEntryPoint authenticationEntryPoint;

    @Resource
    private MyAccessDeniedHandler accessDeniedHandler;

    //登录成功
    @Resource
    private CustomizeAuthenticationSuccessHandler authenticationSuccessHandler;

    @Resource
    private MyAuthenticationSuccessHandler successHandler;

    //登陆失败
    @Resource
    private CustomizeAuthenticationFailureHandler authenticationFailureHandler;

    @Resource
    private CustomizeLogoutSuccessHandler logoutSuccessHandler;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    //将加密规则 注入到spring容器中
    @Bean
    PasswordEncoder password(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //配置认证方式
        auth.userDetailsService(userDetailsService).passwordEncoder(password());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //http相关的配置，包括登入登出、异常处理、会话管理等
        http.cors().and().csrf().disable();

        http.authorizeRequests().
                antMatchers("/getUser").hasAuthority("ROLE_admin").  //hasAuthority方法严格区分大小写
                antMatchers("/comic/test", "/friend/test").access("hasAuthority('ROLE_admin')").
                antMatchers("/comic/getAllComicWithAdminAuthority/**", "/comic/getComicByIdWithAdminAuthority/**", "/comic/getComicByNameWithAdminAuthority/**",
                        "/comic/addComic", "/comic/updateComic", "/comic/deleteComic").access("hasAuthority('ROLE_admin')").
                antMatchers("/friend/getAllFriendWithAdminAuthority/**", "/friend/getFriendByIdWithAdminAuthority/**", "/friend/getFriendByNameWithAdminAuthority/**",
                        "/friend/addFriend", "/friend/updateFriend", "/friend/deleteFriend").access("hasAuthority('ROLE_admin')").
                antMatchers("/user/hasUser", "/user/changePassword", "/user/addUserCollect", "/user/deleteUserCollect").access("hasAnyAuthority('ROLE_customer', 'ROLE_admin')").
                anyRequest().permitAll().
                //异常处理(权限拒绝、登录失效等)
                and().
//                httpBasic().
                exceptionHandling().
                accessDeniedHandler(accessDeniedHandler).     //处理403错误异常
                authenticationEntryPoint(authenticationEntryPoint); //匿名用户访问无权限资源时的异常处理

        http.formLogin().
//                loginPage("/").
                usernameParameter("username").
                passwordParameter("password").
                loginProcessingUrl("/login").
//                successForwardUrl("/admin/success").
                successHandler(authenticationSuccessHandler).  //不能和successForwardUrl共存，不然会报错
                failureHandler(authenticationFailureHandler);

        //退出登陆
        http.logout()
                //自定义退出登录逻辑
                .logoutUrl("/logout")
                .logoutSuccessHandler(logoutSuccessHandler);

        //记住我
        http.rememberMe()
                .tokenValiditySeconds(60)  //设置记住我的过期时间，以秒为单位，默认时间是两周
                //自定义登陆逻辑
                .userDetailsService(userDetailsService)
                .rememberMeParameter("rememberMe")  //自定义记住我中的name值
                //持久层对象
                .tokenRepository(persistentTokenRepository);

        // 基于Token不需要session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 添加JWT过滤器
        http.addFilter(new JWTAuthenticationTokenFilter(authenticationManager()));
    }

    @Bean
    public PersistentTokenRepository getPersistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);

        //自动建表，第一次启动的时候开启，之后要注释掉，不然会报错
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
}
